import { CacheUtils } from "../cache";
import { ComUtils } from "../Com";
import { HttpClient } from "../http";
import { ACCESS_TOKEN_CAHCHE_KEY, AUTH_DIRECT_URL, BACKUP_DIR_NAME, BACKUP_NAME } from "./conf";

const client_id = '403567536532-savgm4qhbo6uncve9lctjich5slr4taj.apps.googleusercontent.com'
const API_BASE_URL = 'https://www.googleapis.com'
export class GoogleDriveUtils implements BackupDriver {
    name = 'googledrive';
    public CACHE_KEY = 'googledrive-'
    async init() {

    }
    getAuthUrl() {
        const baseUrl = 'https://accounts.google.com/o/oauth2/v2/auth'
        const query = {
            client_id,
            redirect_uri: AUTH_DIRECT_URL,
            response_type: 'token',
            prompt: 'select_account',
            scope: 'https://www.googleapis.com/auth/drive.file'
        }
        return `${baseUrl}?${ComUtils.queryToString(query)}`
    }
    async auth() {
        return this.getAuthUrl()
    }
    async cancelAuth() {
        await CacheUtils.remove(this.getCacheKey())
    }
    async save(blob: Blob) {
        const accessToken = await CacheUtils.get(this.getCacheKey())
        const headers = {
            Authorization: `Bearer ${accessToken}`,
        }
        const metadataContent = {
            name: BACKUP_NAME,
            mimeType: 'application/zip',
            parents: [BACKUP_DIR_NAME]
        }

        const rootQuery = {
            corpora: 'user',
            q: `name = '${BACKUP_DIR_NAME}'`,
            spaces: 'drive',
        }
        const root = await HttpClient.get<any>(`${API_BASE_URL}/drive/v3/files`, rootQuery, headers).catch(() => undefined)
        if (!root) {
            const rootForm = {
                'name': BACKUP_DIR_NAME,
                'mimeType': 'application/vnd.google-apps.folder'
            }
            const rootMeta = await HttpClient.post<any>(`${API_BASE_URL}/drive/v3/files`, rootForm, headers)
            metadataContent.parents = [rootMeta.id]
        } else {
            metadataContent.parents = [root.id || root.files[0].id]
        }

        const metaQuery = {
            corpora: 'user',
            q: `name = '${BACKUP_NAME}' and '${metadataContent.parents[0]}' in parents`,
            spaces: 'drive',
        }
        const oldMeta = await HttpClient.get<any>(`${API_BASE_URL}/drive/v3/files`, metaQuery, headers).catch(() => undefined)


        if (oldMeta && oldMeta.files && oldMeta.files[0]) {
            metadataContent.parents = []
            const metadata = new Blob([JSON.stringify(metadataContent)], { type: 'application/json' })
            const form = new FormData()
            form.append('metadata', metadata)
            form.append('file', blob)
            await HttpClient.patch(`${API_BASE_URL}/upload/drive/v3/files/${oldMeta.files[0].id}?uploadType=multipart`, form, headers)
        } else {
            const metadata = new Blob([JSON.stringify(metadataContent)], { type: 'application/json' })
            const form = new FormData()
            form.append('metadata', metadata)
            form.append('file', blob)
            await HttpClient.post(`${API_BASE_URL}/upload/drive/v3/files?uploadType=multipart`, form, headers)
        }
    }
    async load() {
        const accessToken = await CacheUtils.get(this.getCacheKey())
        const headers = {
            Authorization: `Bearer ${accessToken}`,
        }

        const rootQuery = {
            corpora: 'user',
            q: `name = '${BACKUP_DIR_NAME}'`,
            spaces: 'drive',
        }
        try {
            const root = await HttpClient.get<any>(`${API_BASE_URL}/drive/v3/files`, rootQuery, headers).catch(() => undefined)
            if (!root) {
                return
            }
            const parent = root.id || root.files[0].id
            if (!parent) {
                return
            }
            const query = {
                corpora: 'user',
                q: `'${parent}' in parents and name = '${BACKUP_NAME}'`,
                spaces: 'drive',
            }
            const meta = await HttpClient.get<any>(`${API_BASE_URL}/drive/v3/files`, query, headers).catch(() => undefined)
            if (!meta || !meta.files) {
                return
            }
            const downloadQuery = {
                alt: 'media',
            }
            const fileId = meta.id || meta.files[0].id
            const res = await HttpClient.httpRequest<Response>('GET',`${API_BASE_URL}/drive/v3/files/${fileId}`, downloadQuery, headers, true).catch(() => undefined)
            if (!res) {
                return
            }
            return {
                id: meta.id,
                file: await res.blob()
            }
        } catch (error) {
            console.log(error)
        }

    }
    async isAuth() {
        const accessToken = await CacheUtils.get(this.getCacheKey())
        return !!accessToken
    }
    async delete() {
        
    }
    public getCacheKey() {
        return this.CACHE_KEY + ACCESS_TOKEN_CAHCHE_KEY
    }
    async getToken(hash: string) {
        const params = new URLSearchParams(hash)
        return params.get('access_token')
    }
    async getCode(_hash: string) {
        return ''
    }
    getTokenExpires(hash: string) {
        const params = new URLSearchParams(hash)
        return params.get('expires_in')
    }
    getTokenWithCode(_code: string, _hash: string): Promise<string | undefined | null> {
        throw new Error("Method not implemented.");
    }

}